package com.xplay.xpocker.room.mahjong.settlement;

import com.xplay.xpocker.constant.ConstantDict;
import com.xplay.xpocker.constant.MessageNoticeEnum;
import com.xplay.xpocker.constant.RoomTypeEnum;
import com.xplay.xpocker.dvo.GameRuMahjongUserState;
import com.xplay.xpocker.dvo.AbstractRoom;
import com.xplay.xpocker.entity.GameHiRoomDTO;
import com.xplay.xpocker.entity.GameHiRoomUser;
import com.xplay.xpocker.entity.GameRuMahjongFraction;
import com.xplay.xpocker.entity.GameRuMahjongLogs;
import com.xplay.xpocker.room.RoomInfoTL;
import com.xplay.xpocker.room.mahjong.AbstractIsolationEventStrategy;
import com.xplay.xpocker.room.mahjong.MahjongConfigProp;
import com.xplay.xpocker.room.mahjong.constant.MKey;
import com.xplay.xpocker.room.mahjong.constant.PbTypeEnum;
import com.xplay.xpocker.room.mahjong.dto.*;
import com.xplay.xpocker.room.mahjong.event.UserEvent;
import com.xplay.xpocker.room.mahjong.util.MahjongHuUtil;
import com.xplay.xpocker.room.message.MessageContent;
import com.xplay.xpocker.room.message.MessageContentFactory;
import com.xplay.xpocker.room.message.MessageToClient;
import com.xplay.xpocker.room.message.MessageType;
import com.xplay.xpocker.service.GameHiMahjongActionService;
import com.xplay.xpocker.service.GameRuMahjongLogsService;
import com.xplay.xpocker.util.CardUtil;
import com.xplay.xpocker.util.ObjectUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Slf4j
@Component
public class WzIsolationEvent extends AbstractIsolationEventStrategy {

    @Autowired
    private GameRuMahjongLogsService userRuActionLogService;

    @Override
    protected RoomTypeEnum strategyName() {
        return RoomTypeEnum.WZ_MAHJONG;
    }

    @Override
    public void settlementBar(GameRuMahjongUserState currentUser, GameRuMahjongUserState exportUser, Integer type, Integer card, AbstractRoom<MahjongRoomRule, MahjongRoomInfo, GameRuMahjongLogs> roomInfo) {
        PbTypeEnum ofType = PbTypeEnum.ofType(type);
        int fraction = 0;
        if (ofType.equals(PbTypeEnum.MING_BAR) || ofType.equals(PbTypeEnum.DARK_BAR)) {
            // 明杠 和  暗杠
            fraction = 2;
            if (ofType.equals(PbTypeEnum.MING_BAR)) {
                fraction = 1;
            }
        } else {
            fraction = 3;
        }
        if (roomInfo.getRule().checkExistsRule(WzRuleEnum.QSHS.getCode()) && (roomInfo.getGameInfo().getDiskPartExportAllCard().size() <= 3 || CardUtil.buildCard(roomInfo.getGameInfo().getCards()).length <= 3)) {
            fraction *= 2;
        }
        settlement(currentUser, exportUser, ofType.getName(), ofType.getName(), fraction, roomInfo, null);
    }

    @Override
    public void settlementHu(GameRuMahjongUserState currentUser, GameRuMahjongUserState exportUser, Integer exportCard, AbstractRoom<MahjongRoomRule, MahjongRoomInfo, GameRuMahjongLogs> roomInfo) {
        ScoreInfo scoreInfo = checkHu(currentUser, exportUser, exportCard, roomInfo);
        int totalScore = scoreInfo.getTotalScore();
        // 自摸家底还是加番
        if (exportUser == null) {
            // 自摸的时候需要判断其它用户是不是也报听了
            settlement(currentUser, null, String.format("自摸[%s]", scoreInfo.getName()), String.format("被自摸[%s]", scoreInfo.getName()), totalScore, roomInfo, (targetUser) -> {
                if (targetUser.isListen()) {
                    int maxMultiple = scoreInfo.getMultiple() + 1;
                    // 如果开启了 封顶  这里要降级
                    if (roomInfo.getRule().getTurns() > 0 && maxMultiple > roomInfo.getRule().getTurns()) {
                        return scoreInfo.getTotalScore(roomInfo.getRule().getTurns());
                    } else {
                        return scoreInfo.getTotalScore(maxMultiple);
                    }
                }
                return scoreInfo.getTotalScore();
            });
        } else {
            if (exportUser.checkUserMingBar()) {
                // 用户移出手牌
                exportUser.removeCard(exportCard);
                // 构建消息通知
                List<MessageContent<MessageToClient>> messageList = MessageContentFactory.
                        init(roomInfo.getCode(), MessageType.ACTION.getType(), currentUser.getUserId(), MessageNoticeEnum.ALL)
                        .multi(MKey.exeActionUid, exportUser.getUserId(),
                                MKey.cardCode, exportCard,
                                MKey.type, MahjongActionEnum.SNATCH_BAR.getAction())
                        .send().getMessageList();
                RoomInfoTL.addMessageToClient(messageList);
            }
            settlement(currentUser, exportUser, String.format("放炮[%s]", scoreInfo.getName()), String.format("点炮[%s]", scoreInfo.getName()), totalScore, roomInfo, null);
        }
    }

    @Override
    public void presentSettlement(AbstractRoom<MahjongRoomRule, MahjongRoomInfo, GameRuMahjongLogs> roomInfo, GameHiRoomDTO gameHiRoomDTO) {

        // 获取桌面上还有没有牌
        String diskCards = roomInfo.getGameInfo().getCards();
        // 桌面上还有牌
        if (ObjectUtils.isEmpty(diskCards)) {
            // 获取所有未胡牌的用户
            List<GameRuMahjongUserState> notWinUsers = roomInfo.getGameInfo().getAllUser().stream().filter(item -> !item.isWin()).collect(Collectors.toList());
            // 取出下叫的用户
            List<GameRuMahjongUserState> callUsers = notWinUsers.stream().filter(item -> checkListenCards(item, roomInfo) != null).collect(Collectors.toList());
            // 用户全部下叫  退出
            if (notWinUsers.size() != callUsers.size()) {

                /**
                 * 没有下叫的用户  开始赔钱
                 */
                List<GameRuMahjongUserState> notCallUsers = notWinUsers.stream().filter(item -> checkListenCards(item, roomInfo) == null).collect(Collectors.toList());
                for (GameRuMahjongUserState callUser : callUsers) {
                    List<EFScoreInfo> scoreInfos = checkListenCards(callUser, roomInfo);
                    ScoreInfo scoreInfo = scoreInfos.get(0).getScoreInfo();
                    int totalScore = scoreInfo.getTotalScore();
                    for (GameRuMahjongUserState notCallUser : notCallUsers) {
                        settlement(callUser, notCallUser, String.format("赔叫[%s]", scoreInfo.getName()), String.format("赔叫[%s]", scoreInfo.getName()), totalScore, roomInfo, (targetUser) -> {
                            if (targetUser.isListen()) {
                                int maxMultiple = scoreInfo.getMultiple() + 1;
                                // 如果开启了 封顶  这里要降级
                                if (roomInfo.getRule().getTurns() > 0 && maxMultiple > roomInfo.getRule().getTurns()) {
                                    return scoreInfo.getTotalScore(roomInfo.getRule().getTurns());
                                } else {
                                    return scoreInfo.getTotalScore(maxMultiple);
                                }
                            }
                            return scoreInfo.getTotalScore();
                        });

                    }
                }
            }

        }


        /**
         * TODO
         * 这里没有完成工作，这里还没有考虑到 退税，赔叫
         * 1. 如果没有牌可发了,需要取出所有没有听牌的,执行赔叫
         */
        for (GameRuMahjongUserState user : roomInfo.getGameInfo().getAllUser()) {
            if (ObjectUtils.notEmpty(user.getFractions())) {
                int totalSoc = user.getFractions().stream().mapToInt(GameRuMahjongFraction::getFraction).sum();
                Optional<GameHiRoomUser> saveLogUser = gameHiRoomDTO.getAllUsers().stream().filter(item -> item.getUserId().equals(user.getUserId())).findFirst();
                saveLogUser.ifPresent(gameHiRoomUser -> gameHiRoomUser.setScore(totalSoc));
                user.setScore(user.getScore() + totalSoc);
            }
        }

    }

    @Override
    public ScoreInfo checkHu(GameRuMahjongUserState currentUser, GameRuMahjongUserState exportUser, Integer card, AbstractRoom<MahjongRoomRule, MahjongRoomInfo, GameRuMahjongLogs> roomInfo) {
        StringBuilder huBuilder = new StringBuilder("\n");
        huBuilder.append("------------------房间号:").append(roomInfo.getCode()).append(" 胡牌检测------------------").append("\n");
        MahjongRoomInfo gameInfo = roomInfo.getGameInfo();
        StringBuilder fractionInfo = new StringBuilder();
        // 成都麻将 算胡牌了哟
        List<Integer> handCards = currentUser.allHandCards();
        huBuilder.append("【检测用户】:").append(currentUser.getUsername()).append("\n");
        huBuilder.append("【用户手牌】:").append(handCards).append("\n");
        // 使用流进行深度拷贝
        List<Integer> copeHandCards = handCards.stream().map(Integer::new).collect(Collectors.toList());
        // 有时候是为了胡牌自检测，所以这里双重判断 判断手牌是否需要添加这一张牌
        if (card != null && copeHandCards.size() % 3 == 1) {
            copeHandCards.add(card);
        }
        if (exportUser != null) {
            huBuilder.append("【被检测人】:").append(exportUser.getUsername()).append("\n");
            huBuilder.append("【出牌信息】:").append(card).append("\n");
        }

        // 如果没有胡牌 这里可以直接滚蛋了
        if (!MahjongHuUtil.canHu(copeHandCards, 0, true)) {
            huBuilder.append("【胡牌信息】:未能胡牌");
            log.debug(huBuilder.toString());
            return null;
        }
        huBuilder.append("【手牌】:").append(copeHandCards).append("\n");
        int multiple = 0;
        // 出牌人报听加番
        if (exportUser != null && exportUser.isListen()) {
            fractionInfo.append("报听、");
            multiple += 1;
        }
        // 胡牌人报听 加番
        if (currentUser.isListen()) {
            multiple++;
            fractionInfo.append("报听、");
        }
        if (exportUser == null && currentUser.checkUserMingBar()) {
            multiple += 1;
            fractionInfo.append("杠上花、");
        }
        // 出牌人明杠   加番
        if (exportUser != null && exportUser.checkUserMingBar()) {
            multiple += 1;
            fractionInfo.append("抢杠、");
            // 出牌人 暗杠 点炮 加番
        } else if (exportUser != null && exportUser.checkBarShooting()) {
            multiple += 1;
            fractionInfo.append("杠上炮、");
        }
        // 自己杠上花
        if (exportUser == null && currentUser.checkBarBlossom()) {
            multiple += 1;
            fractionInfo.append("杠上花、");
        }

        // 如果前三后四
        if (roomInfo.getRule().checkExistsRule(WzRuleEnum.QSHS.getCode()) && (roomInfo.getGameInfo().getDiskPartExportAllCard().size() <= (exportUser != null ? 4 : 3) || CardUtil.buildCard(gameInfo.getCards()).length <= 3)) {
            multiple += 1;
            fractionInfo.append("前三后四、");
        }
        // 清一色加番
        int classCount = judgeUserCardClass(currentUser, card);
        if (classCount == 1) {
            fractionInfo.append("清一色、");
            multiple += 1;
            // 这里是不是应该开启前三后四才判断
            if (roomInfo.getRule().checkExistsRule(WzRuleEnum.QSHS.getCode()) && currentUser.getOpenDeal() != null && currentUser.getOpenDeal().size() > 2) {
                fractionInfo.append("撞三搭、");
                multiple += 1;
            }
        }
        if (MahjongHuUtil.checkPokerAA(copeHandCards, 0)) {
            fractionInfo.append("七对、");
            multiple++;
        } else if (MahjongHuUtil.canHu(copeHandCards, 0, false)) {
            fractionInfo.append("大队子、");
            multiple++;
            // 七对加番
        }

        // 如果手牌是14张  龙  加番
        if (MahjongHuUtil.checkPokerAA(copeHandCards, 0) && copeHandCards.size() == 14) {
            int size = new HashSet<>(copeHandCards).size();
            if (size == 4) {
                multiple += 3;
                fractionInfo.append("暗三龙、");
            } else if (size == 5) {
                multiple += 2;
                fractionInfo.append("暗双龙、");
            } else if (size == 6) {
                multiple += 1;
                fractionInfo.append("暗龙、");
            }
        }
        //金勾勾 加一番
        if (copeHandCards.size() == 2) {
            multiple++;
            fractionInfo.append("金勾勾、");
        }
        if (multiple == 0) {
            fractionInfo.append("小胡、");
        }

        if (fractionInfo.length() > 0) {
            fractionInfo.deleteCharAt(fractionInfo.length() - 1);
        }
        huBuilder.append("【胡牌倍数】:").append(multiple).append("\n").append("【胡牌信息】:").append(fractionInfo).append("\n");

        // 如果自摸  开启了小胡不走
        if (roomInfo.getRule().checkExistsRule(WzRuleEnum.XHBZ.getCode()) && multiple == 0 && exportUser == null) {
            huBuilder.append("小胡不走已开启");
            log.debug(huBuilder.toString());
            return null;
        }
        // 如果自摸  开启了小胡加番
        if (roomInfo.getRule().checkExistsRule(WzRuleEnum.YHJB.getCode()) && multiple == 0 && exportUser == null) {
            multiple++;
            fractionInfo.append("硬胡加倍、");
        }
        // 万州麻将小胡 放炮是不能走的
        if (multiple == 0 && exportUser != null) {
            huBuilder.append("用户小胡");
            log.debug(huBuilder.toString());
            return null;
        }
        // 如果开启了 封顶  这里要降级
        if (roomInfo.getRule().getTurns() > 0 && multiple > roomInfo.getRule().getTurns()) {
            multiple = roomInfo.getRule().getTurns();
        }
        log.debug(huBuilder.toString());
        return new ScoreInfo(multiple, fractionInfo.toString());
    }

    /**
     * 开始出牌  事件检测
     */
    public void gameStartActionCheck(AbstractRoom<MahjongRoomRule, MahjongRoomInfo, GameRuMahjongLogs> roomInfo) {
        // 检测所有玩家是否 报听,检测庄家是否天胡
        MahjongRoomInfo gameInfo = roomInfo.getGameInfo();
        for (GameRuMahjongUserState userDTO : gameInfo.getAllUser()) {
            List<Integer> userAllCards = userDTO.allHandCards();
            List<MahjongHuUtil.CardEHInfo> cardEHInfos = checkExportListenCards(userDTO);
            if (cardEHInfos.size() > 0 && roomInfo.getRule().checkExistsRule(WzRuleEnum.QSHS.getCode()) && roomInfo.getGameInfo().getDiskPartExportAllCard().size() <= 3) {
                // 为每一位玩家添加报听
                addWaitCompleted(userDTO, MahjongActionEnum.CALL);
                if (userAllCards.size() % 3 != 2) {
                    addWaitCompleted(userDTO, MahjongActionEnum.PASS);
                }
            }
            // 庄家单独处理
            if (userAllCards.size() % 3 == 2) {
                addWaitCompleted(userDTO, MahjongActionEnum.EXPORT_CARD);
                if (checkHu(userDTO, null, null, roomInfo) != null) {
                    addWaitCompleted(userDTO, MahjongActionEnum.HU);
                }
                // 庄家还有暗杠检测
                List<Integer> barCardArray = checkUserDarkBar(userDTO);
                if (barCardArray.size() > 0) {
                    addWaitCompleted(userDTO, MahjongActionEnum.BAR_CARD);
                }
            }
            // 塞子转动一秒  交换动画三秒
            notifyUserActionUpdate(userDTO, 5);
        }
    }
    /**
     *
     *
     * -- 距离最新一次摸牌   这个时间内 是否存在   碰牌 + PASS
     * select * from game_ru_mahjong_logs b where b.id >
     * (SELECT min(id) FROM `game_ru_mahjong_logs` a where a.source_user_id = 1 and a.source_user_id = b.source_user_id and a.action = 'TOUCH')
     * and (b.action = 'BUMP' or b.action = 'TOUCH')
     *
     */

    /**
     * 发牌事件检测
     */
    public void dealCardActionCheck(GameRuMahjongUserState nextUser, Integer nextCard, AbstractRoom<MahjongRoomRule, MahjongRoomInfo, GameRuMahjongLogs> roomInfo) {
        // 检测当前 玩家  是否胡牌，是否可以杠牌  是否可以报听
        log.debug("房间号:{},桌面牌数:{}", roomInfo.getCode(), roomInfo.getGameInfo().getDiskPartExportAllCard().size());
        MahjongMessage touchCardMessage = MahjongMessage.Builder.builder().cardCode(nextCard).exeActionUid(nextUser.getUserId())
                // 设置事件
                .type(MahjongActionEnum.TOUCH.getAction())
                // 指定目标对象  指定谁执行
                .build();
        //  构建 摸牌用户  胡牌 杠牌 出牌  等操作
        addWaitCompleted(nextUser, MahjongActionEnum.EXPORT_CARD);
        //  判断用户是否能杠
        if ((ObjectUtils.notEmpty(checkUserDarkBar(nextUser)) || ObjectUtils.notEmpty(checkUserMingBar(nextUser))) && checkListenUserBar(nextUser, nextCard)) {
            addWaitCompleted(nextUser, MahjongActionEnum.BAR_CARD);
        }
        //  判断用户是否能报听   注意这里要前四, 开发阶段忽略
        if (ObjectUtils.notEmpty(checkExportListenCards(nextUser)) && !nextUser.isListen() && roomInfo.getRule().checkExistsRule(WzRuleEnum.QSHS.getCode()) && roomInfo.getGameInfo().getDiskPartExportAllCard().size() <= 3) {
            addWaitCompleted(nextUser, MahjongActionEnum.CALL);
        }
        // 判断用户是否能胡牌
        if (checkHu(nextUser, null, null, roomInfo) != null) {
            addWaitCompleted(nextUser, MahjongActionEnum.HU);
        }
        // 如果用户报听，然后这个用户又能胡牌,不添加  过牌事件
        if (nextUser.isListen() && nextUser.checkUserExistAction(MahjongActionEnum.HU)) {
            nextUser.removeUserAction(MahjongActionEnum.PASS, MahjongActionEnum.EXPORT_CARD);
        }
        // 用户报听，然后用户有只能出牌

        if ((nextUser.isListen() || nextUser.isOnHook()) && nextUser.checkUserSingWaitCompleted(MahjongActionEnum.EXPORT_CARD)) {
            /**
             * TODO
             * 构建自动出牌....
             */
            MahjongMessage exportCardMessage = MahjongMessage.Builder.builder().cardCode(nextCard).messageFromUserId(nextUser.getUserId())
                    // 设置事件
                    .type(MahjongActionEnum.EXPORT_CARD.getAction()).exeActionUid(nextUser.getUserId())
                    // 指定目标对象  指定谁执行
                    .build();
            MessageContent messageContent = MessageContent.Builder.builder()
                    // 设置牌
                    .setBody(exportCardMessage).setRoomCode(roomInfo.getCode()).setType(MessageType.ACTION.getType()).build();
            applicationEventPublisher.publishEvent(new UserEvent(this, messageContent));
        }
        double delay = 0.5;
        notifyUserActionUpdate(nextUser, 0.5);
        List<MessageContent<MessageToClient>> messageList = MessageContentFactory.init(roomInfo.getCode(), MessageType.ACTION.getType(), nextUser.getUserId(), MessageNoticeEnum.CURRENT).multi(MKey.exeActionUid, nextUser.getUserId(), MKey.type, MahjongActionEnum.TOUCH.getAction(), MKey.cardCode, nextCard).send().filter(MessageNoticeEnum.OTHER, MahjongConfigProp.getInstance().isDesensitize() ? MKey.cardCode : null).send().getMessageList();
        RoomInfoTL.addMessageToClient(messageList, delay);
    }

    /**
     * 是否缺一门 missingOne
     * 是否定雀   isConfirm
     * 是否幺鸡   yaoChicken
     * 是否小胡不走
     *
     * @param currentUser
     * @return
     */

    @Override
    public List<EFScoreInfo> checkListenCards(GameRuMahjongUserState currentUser, AbstractRoom<MahjongRoomRule, MahjongRoomInfo, GameRuMahjongLogs> roomInfo) {
        // 用户胡那些牌
        List<Integer> huCards = MahjongHuUtil.checkHInfo(currentUser.allHandCards(), 0);
        if (huCards.size() == 0) {
            return null;
        }
        ArrayList<EFScoreInfo> scoreInfos = new ArrayList<>();
        for (Integer huCard : huCards) {
            scoreInfos.add(new EFScoreInfo(huCard, checkHu(currentUser, null, huCard, roomInfo)));
        }
        scoreInfos.sort(Comparator.comparingInt(EFScoreInfo::getMultiple).reversed());
        return scoreInfos;
    }

    @Override
    public List<MahjongHuUtil.CardEHInfo> checkExportListenCards(GameRuMahjongUserState currentUser) {
        return MahjongHuUtil.checkEHInfo(currentUser.allHandCards(), 0);
    }

    /**
     * 出牌     事件检测
     * 记录一下 别人  碰  杠  胡
     */
    public boolean exportCardActionCheck(GameRuMahjongUserState current, Integer exportCard, AbstractRoom<MahjongRoomRule, MahjongRoomInfo, GameRuMahjongLogs> roomInfo) {
        // 检测其它玩家 是否可以胡牌   是否可以杠牌  是否可以碰牌
        boolean loading = false;
        /**
         * 用户已经执行听牌事件
         * 两种情况
         * 1. 摸牌后听
         * 2. 先听摸牌
         */
        if (current.isListen() && ObjectUtils.notEmpty(current.getListenCards())) {
            List<Integer> listenCardsArray = CardUtil.buildCardList(current.getListenCards());
            if (listenCardsArray.size() % 3 == 2) {
                CardUtil.removeCard(listenCardsArray, exportCard);
                current.setListenCards(CardUtil.joinCard(listenCardsArray));
            }
        }
        /**
         * 没有过庄  就不能  碰杠胡
         */

        for (GameRuMahjongUserState otherUser : roomInfo.getGameInfo().getAllUser()) {
            if (otherUser.getUserId().equals(current.getUserId())) {
                continue;
            }
            if (otherUser.isWin()) {
                continue;
            }
            List<GameRuMahjongLogs> actionLogs = userRuActionLogService.queryUserTouchAfterAction(otherUser.getUserId());

            int tally = otherUser.checkTally(exportCard);
            // 碰牌必须判断用户没有报听
            if (tally >= ConstantDict.Mahjong.HAND_TWO_COUNT && !otherUser.isListen() && checkUserPassAction(actionLogs, MahjongActionEnum.BUMP) == null) {
                // 能碰
                loading = true;
                addWaitCompleted(otherUser, MahjongActionEnum.BUMP);
                // 记录一下用户可以执行碰牌
                GameRuMahjongLogs.GameRuMahjongLogsBuilder logsBuilder = GameRuMahjongLogs.builder().type(ConstantDict.MahjongLogType.USER).action(MahjongActionEnum.BUMP.getAction()).roomId(roomInfo.getId()).sourceUserId(current.getUserId()).targetUserId(otherUser.getUserId()).cardCode(exportCard);
                RoomInfoTL.addLog(logsBuilder.build());
            }
            // 杠牌  必须判断用户不能变叫

            if (tally >= ConstantDict.Mahjong.HAND_THREE_COUNT && checkListenUserBar(otherUser, exportCard) && checkUserPassAction(actionLogs, MahjongActionEnum.BAR_CARD) == null) {
                // 能杠
                loading = true;
                addWaitCompleted(otherUser, MahjongActionEnum.BAR_CARD);
                // 记录一下用户可以执行 杠牌
                GameRuMahjongLogs.GameRuMahjongLogsBuilder logsBuilder = GameRuMahjongLogs.builder().type(ConstantDict.MahjongLogType.USER).action(MahjongActionEnum.BAR_CARD.getAction()).roomId(roomInfo.getId()).sourceUserId(current.getUserId()).targetUserId(otherUser.getUserId()).cardCode(exportCard);
                RoomInfoTL.addLog(logsBuilder.build());
            }
            ScoreInfo scoreInfo = checkHu(otherUser, current, exportCard, roomInfo);
            if (scoreInfo != null && checkUserPassAction(actionLogs, MahjongActionEnum.HU) == null) {
                loading = true;
                //能胡
                addWaitCompleted(otherUser, MahjongActionEnum.HU);
                // 记录一下用户可以执行 杠牌
                GameRuMahjongLogs.GameRuMahjongLogsBuilder logsBuilder = GameRuMahjongLogs.builder().type(ConstantDict.MahjongLogType.USER).action(MahjongActionEnum.HU.getAction()).multiple(scoreInfo.getMultiple()).roomId(roomInfo.getId()).sourceUserId(current.getUserId()).targetUserId(otherUser.getUserId()).cardCode(exportCard);
                RoomInfoTL.addLog(logsBuilder.build());
            }
            if (ObjectUtils.notEmpty(otherUser.getWaitCompleted())) {
                addWaitCompleted(otherUser, MahjongActionEnum.PASS);
            }
            // 如果用户报听，然后这个用户又能胡牌,不添加  过牌事件
            if (otherUser.isListen() && otherUser.checkUserExistAction(MahjongActionEnum.HU)) {
                otherUser.removeUserAction(MahjongActionEnum.PASS);
            }
            notifyUserActionUpdate(otherUser, 0);
        }
        return loading;
    }

    /**
     * 判断两个集合是否相等
     *
     * @param list1
     * @param list2
     * @return
     */

    public static boolean areListsEqual(List<Integer> list1, List<Integer> list2) {
        if (list1.size() != list2.size()) {
            return false;
        }
        List<Integer> sortedList1 = list1.stream().sorted().collect(Collectors.toList());
        List<Integer> sortedList2 = list2.stream().sorted().collect(Collectors.toList());
        return sortedList1.equals(sortedList2);
    }

    /***
     * 当用户移出这张牌过后   也就是报听是否可以杠牌
     * 是否影响报听
     * @param userDTO
     * @param cardCode
     * @return
     */

    public boolean checkListenUserBar(GameRuMahjongUserState userDTO, Integer cardCode) {
        if (!userDTO.isListen()) {
            return true;
        }
        // 拿到用户的手牌 深度拷贝
        List<Integer> allHandCards = new ArrayList<>(userDTO.allHandCards());
        // 摸牌会导致满牌  所以这里先做一次移出，发牌不会
        if (allHandCards.size() % 3 == 2) {
            allHandCards.remove(cardCode);
        }
        List<Integer> beforeCheckHInfo = MahjongHuUtil.checkHInfo(allHandCards, 0);
        // 删除手牌
        allHandCards = allHandCards.stream().filter(card -> !card.equals(cardCode)).collect(Collectors.toList());
        List<Integer> afterCheckHInfo = MahjongHuUtil.checkHInfo(allHandCards, 0);
        if (ObjectUtils.isEmpty(beforeCheckHInfo) || ObjectUtils.isEmpty(afterCheckHInfo)) {
            return false;
        }
        return areListsEqual(beforeCheckHInfo, afterCheckHInfo);

    }

    /**
     * 碰牌     事件检测
     */
    public void bumpCardActionCheck(AbstractRoom<MahjongRoomRule, MahjongRoomInfo, GameRuMahjongLogs> roomInfo, GameRuMahjongUserState current, GameRuMahjongUserState source, Integer cardCode) {
        //  判断用户是否能杠
        if (ObjectUtils.notEmpty(checkUserDarkBar(current)) || ObjectUtils.notEmpty(checkUserMingBar(current))) {
            addWaitCompleted(current, MahjongActionEnum.BAR_CARD);
        }
        //  判断用户是否能报听   注意这里要前四, 开发阶段忽略
        if (ObjectUtils.notEmpty(checkExportListenCards(current)) && !current.isListen() && roomInfo.getRule().checkExistsRule(WzRuleEnum.QSHS.getCode()) && (roomInfo.getGameInfo().getDiskPartExportAllCard().size() <= 3 || CardUtil.buildCard(roomInfo.getGameInfo().getCards()).length <= 3)) {
            addWaitCompleted(current, MahjongActionEnum.CALL);
        }
        notifyUserActionUpdate(current, 0);
    }

    /**
     * 杠牌     事件检测
     */
    public void userBarActionCheck() {
        // 暗杠 摸牌 并检测当前 玩家是否可以胡牌
        // 明杠 先检测其它晚间是否可以抢杠，再摸牌
    }

    @Override
    public void checkUserAction(AbstractRoom<MahjongRoomRule, MahjongRoomInfo, GameRuMahjongLogs> roomInfo) {
        MahjongRoomInfo gameInfo = roomInfo.getGameInfo();
        // 桌面上已经出牌的总数
        List<Integer> diskPartExportAllCard = gameInfo.getDiskPartExportAllCard();

        /**
         *
         * 交换完毕  事件检测
         * 发牌     事件检测
         * 摸牌     事件检测
         * 碰牌     事件检测
         * 杠牌     事件检测
         *
         *
         * 发牌
         * 换三张
         * 检测 每一个玩家是否报听，检测庄家是否天胡
         * 玩家出牌
         * (前四张) 可以直接判定胡牌
         * 玩家摸牌
         * (前四张) 判定是否报听
         */
    }

}
